package cDB

import (
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"

	"gitee.com/csingo/cCommon"

	"gitee.com/csingo/cLog"
)

func findGormClient(ctx *gin.Context, name string) *gorm.DB {
	if client, _ := ctx.Get(cCommon.Context_GormDBTransaction); client != nil {
		return client.(*gorm.DB)
	} else {
		client := Client[*gorm.DB](ctx, name)
		if client == nil {
			cLog.WithContext(ctx, map[string]any{
				"source":     "cDB.findGormClient",
				"connection": name,
			}).Panic("database connection is not exists")
		}

		return client
	}
}

// WithContextTable 仅用于 gorm，使用table进行查询
func WithContextTable(ctx *gin.Context, model ModelInterface) *gorm.DB {
	name := model.Connection(ctx)
	client := findGormClient(ctx, name)

	query := client.WithContext(ctx)
	connector := container.GetConnector(name)
	if connector == nil {
		cLog.WithContext(ctx, map[string]any{
			"source":    "cDB.WithContextModel",
			"connector": name,
		}).Error("database connector is not exists")
		return query
	}
	driver := connector.GetDriver()
	if driver.IsDebug() {
		query = query.Debug()
	}

	table := model.TableName()
	query = query.Table(table)

	return query
}

// WithContextModel 仅用于 gorm，使用model实体进行查询
func WithContextModel(ctx *gin.Context, model ModelInterface) *gorm.DB {
	name := model.Connection(ctx)
	client := findGormClient(ctx, name)

	query := client.WithContext(ctx).Model(model)
	connector := container.GetConnector(name)
	if connector == nil {
		cLog.WithContext(ctx, map[string]any{
			"source":    "cDB.WithContextModel",
			"connector": name,
		}).Error("database connector is not exists")
		return query
	}
	driver := connector.GetDriver()
	if driver.IsDebug() {
		query = query.Debug()
	}

	table := model.TableName()
	query = query.Table(table)

	return query
}

func StartTransaction(ctx *gin.Context, name string, f func(ctx *gin.Context, tx *gorm.DB) error) error {
	client := Client[*gorm.DB](ctx, name)
	err := client.Transaction(func(tx *gorm.DB) error {
		newCtx := ctx.Copy()
		newCtx.Set(cCommon.Context_GormDBTransaction, tx)
		defer newCtx.Set(cCommon.Context_GormDBTransaction, nil)
		err := f(newCtx, tx)
		return err
	})

	return err
}

func StartTransactionWithModel(ctx *gin.Context, model ModelInterface, f func(ctx *gin.Context, tx *gorm.DB) error) error {
	client := Client[*gorm.DB](ctx, model.Connection(ctx))
	err := client.Transaction(func(tx *gorm.DB) error {
		newCtx := ctx.Copy()
		newCtx.Set(cCommon.Context_GormDBTransaction, tx)
		defer newCtx.Set(cCommon.Context_GormDBTransaction, nil)
		err := f(newCtx, tx)
		return err
	})

	return err
}
